#include "json_utils.h"

#define DEBUG

char memStructure[MEM_SIZE_STRUCTURE];
char memJsonData[MEM_SIZE_JSONDATA];
char memJsonParse[MEM_SIZE_JSONPARSEDATA];
/******************************************
*Structure Memory Manager
*******************************************/
char *structureBasePtr = memStructure;
char *structureCurrPtr = memStructure;
int structureMemCnt = 0;

//malloc jsonPair
JsonPair *jsonPairMalloc(){
		void *ptr = structureCurrPtr;
		int size = sizeof(JsonPair);
	  structureMemCnt += size;
		if(structureMemCnt > MEM_SIZE_STRUCTURE)
				return NULL;
		structureCurrPtr = structureCurrPtr + structureMemCnt;
		
		return (JsonPair *)ptr;
}

//malloc jsonObj
JsonObject *jsonObjectMalloc(){
		void *ptr = structureCurrPtr;
		int size = sizeof(JsonObject);
	  structureMemCnt += size;
	  if(structureMemCnt > MEM_SIZE_STRUCTURE)
				return NULL;
		structureCurrPtr = structureCurrPtr + structureMemCnt;
		return (JsonObject *)ptr;
}

char *structureMemFree(){
		memset(memJsonData, 0, MEM_SIZE_STRUCTURE);
		structureBasePtr = memJsonData;
		structureCurrPtr = memJsonData;
	  structureMemCnt = 0;
 		return structureBasePtr;
}

/******************************************
*Data Memory Manager
*******************************************/
char *dataBasePtr = memJsonData;
char *dataCurrPtr = memJsonData;
int dataMemIndex = 0;

//malloc json data memory
char *dataMemMalloc(int size){
		char *ptr = dataCurrPtr;
		dataCurrPtr = dataCurrPtr + size;
		return ptr;
}

//free json data memory
char *dataMemFree(){
		memset(dataBasePtr, 0, MEM_SIZE_JSONDATA);
		dataBasePtr = dataBasePtr;
	  dataCurrPtr = dataBasePtr;
	  dataMemIndex = 0;
		return dataBasePtr;
}
/******************************************
*Data Memory Manager
*******************************************/
char *memJsonParseFree(){
		memset(dataBasePtr, 0, MEM_SIZE_JSONDATA);
}

/****************************************
*  generate json 
*****************************************/
JsonObject *createJsonObject(){
		
		JsonObject *ptr = jsonObjectMalloc();
		//json-pair header
		ptr->jsonPair = NULL;
	    //json-pair rear
		ptr->lastJsonPair = NULL;
		ptr->length = 0;
		return ptr;
}

//add a normal key-value pair
JsonObject *addJsonPair(JsonObject *rootObject, char *key, char *value){
		
		JsonPair *jsonPair = jsonPairMalloc();
		jsonPair->key = key;
		jsonPair->keyLength = strlen(key);
		jsonPair->value = value;
		jsonPair->valueLength = strlen(value);
		jsonPair->valueType = VALUE_TYPE_NORMALPAIR;
	
		if(rootObject->jsonPair == NULL){
				rootObject->jsonPair = jsonPair;
				rootObject->lastJsonPair = jsonPair;
				//jsonPair->prev = NULL;
				jsonPair->next = NULL;
		}else{
				//jsonPair->prev = rootObject->lastJsonPair;
				jsonPair->next = NULL;
				rootObject->lastJsonPair->next = jsonPair;
				rootObject->lastJsonPair = jsonPair;
		}
		
		rootObject->length++;
		
		return rootObject;
}

//get json key-value as string
char *generateJsonPairString(char *mem, int *index, JsonPair *jsonPair){
		char *str = NULL;
	
		mem[(*index)++] = '"';
		memcpy(mem+(*index), jsonPair->key, jsonPair->keyLength);
		*index = *index + jsonPair->keyLength;
		mem[(*index)++] = '"';   
	
		mem[(*index)++] = ':';
		
		memcpy(mem+(*index), jsonPair->value, jsonPair->valueLength);
		*index = *index + jsonPair->valueLength;
	
		mem[(*index)] = '\0';
		str = mem;
		return str;
}

//add a json object array's address
JsonObject *addJsonObjects(JsonObject *rootObject, char *key, JsonObject **childObject){
	
		JsonPair *jsonPair = jsonPairMalloc();
		jsonPair->key = key;
		jsonPair->keyLength = strlen(key);
		jsonPair->obj = childObject;
		//(*jsonPair->obj)->length = arrayLength;
		jsonPair->valueType = VALUE_TYPE_JSONARRAY;
	
		if(rootObject->jsonPair == NULL){
					
				rootObject->jsonPair = jsonPair;
				rootObject->lastJsonPair = jsonPair;
				//jsonPair->prev = NULL;
				jsonPair->next = NULL;
		}else{
				//jsonPair->prev = rootObject->lastJsonPair;
				jsonPair->next = NULL;
				rootObject->lastJsonPair->next = jsonPair;
				rootObject->lastJsonPair = jsonPair;
		}
		
		rootObject->length++;
	
		return rootObject;
}

//get json array as string
char *generateJsonArrayString(char *mem, int *index, JsonPair *jsonPair){   //JsonObject *jsonObject
	
		char *str = NULL;
		int i = 0, j = 0;
		int length = 0;

		mem[(*index)++] = '"';
		memcpy(mem+(*index), jsonPair->key, jsonPair->keyLength);
		*index = *index + jsonPair->keyLength;
		mem[(*index)++] = '"';   
		mem[(*index)++] = ':';
		mem[(*index)++] = '[';
		
		JsonPair *jsonPairHead;
		JsonObject **jsonObject = jsonPair->obj;
		JsonObject *jsonObjectCurr;		
	
		jsonObjectCurr = jsonObject[0];
		for(j=0; j<jsonPair->jsonObjLength; j++){
			
			jsonPairHead = jsonObjectCurr->jsonPair;
			
			mem[(*index)++] = '{';
			while(jsonPairHead != NULL){
					
					//JsonPair *innerJsonPair = (*jsonPairHead->obj)->jsonPair;
					
					if(jsonPairHead->valueType == VALUE_TYPE_NORMALPAIR){
							//handle normal json pair
							generateJsonPairString(mem, index, jsonPairHead);
					}else if(jsonPairHead->valueType == VALUE_TYPE_JSONARRAY){
							//handle json array pair
							generateJsonArrayString(mem, index, jsonPairHead);
					}
					jsonPairHead = jsonPairHead->next;
				
					
					mem[(*index)++] = ',';
			}
			mem[(*index)-1] = '}';
			mem[(*index)++] = ',';
			
			jsonObjectCurr = jsonObjectCurr->next;
		}
		mem[(*index)-1] = ']';
		mem[(*index)] = '\0';
		
		str = mem;
	  return str;
}

//json generate function
char *generateJsonObjectString(char *mem, int *index, JsonObject *jsonObject){

		char *str = NULL;
		int i;
		int length = jsonObject->length;
		JsonPair *jsonPairPtr = jsonObject->jsonPair;
	
		mem[(*index)++] = '{';
		for(i=0; i<length; i++){
				if(jsonPairPtr->valueType == VALUE_TYPE_NORMALPAIR){
						generateJsonPairString(mem, index, jsonPairPtr);
				}else if(jsonPairPtr->valueType == VALUE_TYPE_JSONOBJ){
						
				}else if(jsonPairPtr->valueType == VALUE_TYPE_JSONARRAY){
						generateJsonArrayString(mem, index, jsonPairPtr);
				}
				jsonPairPtr = jsonPairPtr->next;
				mem[(*index)++] = ',';
		}
		mem[(*index)-1] = '}';
		mem[(*index)] = '\0';
		
		return mem;
}

/****************************************
*  parse json 
*****************************************/

char *copyString(char *dec, char *src, int length){
		
		char *str = NULL;	
		memcpy(dec, src, length);
		dec[length] = '\0';
		str = dec;
		return str;
}

//get string's type
int getStringType(char *str){
		
		int type = -1;
		int i = 0;
		
		while(str[i] == ' ' || str[i] == 10 || str[i] == 29){
				i++;
		}
		if(str[i] == '\0'){
				type = -1;
		}else if(str[i] == '{'){
				type = VALUE_TYPE_JSONOBJ;
		}else if(str[i] == '['){
				type = VALUE_TYPE_JSONARRAY;
		}else{
				type = VALUE_TYPE_NORMALPAIR;
		}
	
		return type;
}

/**
* **strArray      record string's head address
* *lengthArray    record every string's length
* *str            source string
* *index          0  
*/
int devideJsonArrayString(char **strArray, int *lengthArray, char *str, int *index){
	
		int ret = 0;
		int cnt = 0;
		char *start = NULL;
		int lengthRec = *index;
		
		while(str[*index] == ' ' || str[*index] == 10 || str[*index] == 29){
				(*index)++;
		}
		
		while(str[*index] != '\0'){
				if(str[*index] == '{'){
						if(strArray != NULL){
								lengthRec = *index;
						}
						start = &str[*index];
						devideJsonArrayString(NULL, NULL,&str[(*index)], index);
				}else if(str[*index] == '}'){
					
						if(strArray != NULL){        //
								strArray[cnt++] = start;
								lengthArray[cnt++] = *index - lengthRec;
								lengthRec = *index;
						}
						break;
				}
				(*index)++;
		}
		return ret;
}

JsonObject *parseJsonObject(JsonObject *rootJsonObject, char *mem, char* jsonObjectStr, int *index){
	
		int innerIndex = 0;
		int keyValueIndex = 0;
		int keyLength = 0;
		int valueLength = 0;
		int i = 0;
		int startKeyValueFlag = 0;
		int mesureKeyLengthFlag = 0;
	
		char *keyStr = NULL;
		char *valueStr = NULL;
	
		int type = -1;
	
		int arrayLength = 0;
		
		rootJsonObject->jsonPair = NULL;
		rootJsonObject->lastJsonPair = NULL;
		rootJsonObject->length = 0;
		rootJsonObject->next = NULL;
		
		while(jsonObjectStr[i] != '\0'){
			
				if(jsonObjectStr[i] == '"' && startKeyValueFlag == 0){
						startKeyValueFlag = 1;
				}
				
				if(startKeyValueFlag){  //start to parse key-value pair
					
						mesureKeyLengthFlag = 1;
						keyValueIndex = 0;
						keyLength = 0;
						valueLength = 0;
						while(jsonObjectStr[i+keyValueIndex] != ',' && jsonObjectStr[i+keyValueIndex] != '}'){
							
								if(jsonObjectStr[i+keyValueIndex] == '"'){  //measure length of key
										keyValueIndex++;
								}
							
								if(jsonObjectStr[i+keyValueIndex] == ':'){  //measure length of value
										mesureKeyLengthFlag = 0;
								}
							
								if(mesureKeyLengthFlag){
									 keyLength++;
								}else{
									 valueLength++;						
								}
								keyValueIndex++;
						}
						valueLength = valueLength - 1; //skip ','
						
						innerIndex = i;

						//fetch key string
						keyLength = keyLength;
						keyStr = copyString(mem+(*index), &jsonObjectStr[i+1], keyLength);
						*index += (keyLength+2);
						
						//fetch value string  
						valueStr = copyString(mem+(*index), &jsonObjectStr[i+keyLength+3],valueLength);
						*index += (valueLength+1);       //avoid other string rewrite the value's last '\0'         
						
						type = getStringType(valueStr);
						
						//create a jsonPair and add this jsonPair to the rootJsonObject
						JsonPair *jsonPair = jsonPairMalloc();
						jsonPair->key = keyStr;
						jsonPair->keyLength = strlen(keyStr);
						jsonPair->next = NULL;
						if(type == VALUE_TYPE_NORMALPAIR){
								jsonPair->value = valueStr;
						}else if(type == VALUE_TYPE_JSONOBJ){
								
						}else if(type == VALUE_TYPE_JSONARRAY){
								//TODO
								//JsonObject *jsonObject = 
						}
						jsonPair->valueType = type;
						
						if(rootJsonObject->jsonPair == NULL){
								rootJsonObject->jsonPair = jsonPair;
								rootJsonObject->lastJsonPair = rootJsonObject->jsonPair;
						}else{
								rootJsonObject->lastJsonPair->next = jsonPair;
								rootJsonObject->lastJsonPair = rootJsonObject->lastJsonPair->next;
						}
						
						i += keyValueIndex;
						startKeyValueFlag = 0;
				}else{
						i++;
				}
		}
	
		return mem;
}

/*************************************************************************************/
char* testNewJsonGenerateUtil(){

		dataMemIndex = 0;
	
		JsonObject *rootJsonObject = createJsonObject();
		
		//add key-value pair
		addJsonPair(rootJsonObject, "key1", "value1");
	  	addJsonPair(rootJsonObject, "key2", "value2");
	  	addJsonPair(rootJsonObject, "key3", "value3");
	
		//add json array
		JsonObject *jsonObject0 = createJsonObject();
		addJsonPair(jsonObject0, "key40", "value40");
	    addJsonPair(jsonObject0, "key50", "value50");

		JsonObject *jsonObject1 = createJsonObject();
		addJsonPair(jsonObject1, "key41", "value41");
	    addJsonPair(jsonObject1, "key51", "value51");	
		jsonObject0->next = jsonObject1;
		
		addJsonObjects(rootJsonObject, "key_arr1", &jsonObject0);
		rootJsonObject->lastJsonPair->jsonObjLength = 2;
		
		
		//generate json string
		char *str = generateJsonObjectString(dataBasePtr, &dataMemIndex, rootJsonObject);
	
		//clear memory
		//structureMemFree();
		//dataMemFree();
		printf("json string: \n");
		printf(str);
	
		return str;
}

void testNewJsonParseUtil(char *jsonStr){
		
		JsonObject *rootJsonObject = createJsonObject();
		
		int index = 0;
		char *str = parseJsonObject(rootJsonObject, memJsonParse, jsonStr, &index);
		
		printf("\n\njson data:\n");
		printf(rootJsonObject->jsonPair->key);
		printf("\n");
		printf(rootJsonObject->jsonPair->value);
		
		printf("\n");
		printf(rootJsonObject->jsonPair->next->key);
		printf("\n");
		printf(rootJsonObject->jsonPair->next->value);
		
		printf("\n");
		printf(rootJsonObject->jsonPair->next->next->key);
		printf("\n");
		printf(rootJsonObject->jsonPair->next->next->value);
		
		printf("\n\n");
		
		//clear memory
		//structureMemFree();
		//memJsonParseFree();
		//dataMemFree();
}





